/*
Copyright 2007 John Tsiombikas <nuclear@siggraph.org>

This file is part of the pixelshow 2007 invitation demo.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "text_ml.h"
#include "text.h"

enum {
	EMPHASIS,
	HEADING,
	BREAK
};

static void enable(unsigned int st);
static void disable(unsigned int st);
static int is_enabled(unsigned int st);
static const char *eval_tag(const char *ptr);

static unsigned int state;
static unsigned int fonts[TML_MAX_FONT_COUNT];
static vec2_t rect_origin, rect_sz = {1, 1};

void tml_set_font(unsigned int type, unsigned int font_id)
{
	fonts[type] = font_id;

	if(type == TML_FONT_REGULAR) {
		bind_font(font_id);
		tml_set_text_rect(0, get_line_advance(), 1, 1);
	}
}

unsigned int tml_get_font(unsigned int type)
{
	return fonts[type];
}

void tml_set_text_rect(float x, float y, float width, float height)
{
	rect_origin.x = x;
	rect_origin.y = y;
	rect_sz.x = width;
	rect_sz.y = height;
	set_text_pos(x, y);
}

float tml_print_string(const char *str)
{
	static char *span;
	static int span_len = 256;
	float vert_size = 0.0f;

	if(!span) {
		span = malloc(span_len + 1);
	}

	while(*str) {
		const char *ptr = str;
		while(*ptr && *ptr != '<') ptr++;

		if(ptr != str) {
			char *tok;
			vec2_t pos;

			int len = ptr - str;
			if(!span || len > span_len) {
				span_len *= 2;
				span = realloc(span, span_len + 1);
			}
			memcpy(span, str, len);
			span[len] = 0;

			if(is_enabled(HEADING)) {
				bind_font(fonts[TML_FONT_HEADING]);
			} else {
				if(is_enabled(EMPHASIS)) {
					bind_font(fonts[TML_FONT_ITALIC]);
				} else {
					bind_font(fonts[TML_FONT_REGULAR]);
				}
			}

			pos = get_text_pos();
			if(is_enabled(BREAK)) {
				float adv = get_line_advance();
				pos.y += adv;
				pos.x = rect_origin.x;
				disable(BREAK);
				vert_size += adv;
			}
			set_text_pos(pos.x, pos.y);

			tok = strtok(span, " \n\t\r");
			while(tok) {
				char last_char;

				pos = get_text_pos();
				if(pos.x + get_text_width(tok) > rect_sz.x) {
					float adv = get_line_advance();
					pos.y += adv;
					pos.x = rect_origin.x;
					set_text_pos(pos.x, pos.y);
					vert_size += adv;
				}
				print_string(tok);
				last_char = str[tok + strlen(tok) - span];

				tok = strtok(0, " \n\t\r");
				if(tok || isspace(last_char)) {
					print_string(" ");
				}
			}
			/*print_string(span);*/
		}

		if(*ptr == '<') {
			str = eval_tag(ptr);
		} else {
			str = ptr;
		}
	}

	return vert_size;
}

static const char *eval_tag(const char *ptr)
{
	const char *cont;
	void (*action)(unsigned int);

	if(!(cont = strchr(ptr, '>'))) {
		return ptr + 1;
	}
	cont++;

	if(ptr[1] == '!' || ptr[1] == '>' || (ptr[1] == '/' && ptr[2] == '>')) {
		return cont;
	}

	if(ptr[1] == '/') {
		action = disable;
		ptr += 2;
	} else {
		action = enable;
		ptr++;
	}

	switch(*ptr) {
	case 'i':
		action(EMPHASIS);
		break;

	case 'h':
		action(HEADING);
		break;

	case 'b':
		if(ptr[1] == 'r') {
			action(BREAK);
		}
		break;

	default:
		break;
	}

	return cont;
}

void enable(unsigned int st)
{
	state |= (1 << st);
}

void disable(unsigned int st)
{
	state &= ~(1 << st);
}

int is_enabled(unsigned int st)
{
	return (state & (1 << st)) ? 1 : 0;
}
